/*------------------------------------------------------------------------
//                          Project CommonLib                           //
------------------------------------------------------------------------*/

#include "stdafx.h"
#include "DbgAssert.h"


namespace _ASSERT
{
    const TCHAR *AssertWindowTitle = TEXT("ASSERT MESSAGE BOX");
    const TCHAR *AskToInvokeAgain = TEXT("Do you Want to the ASSERT MessageBOX to pop Again ?");
}

static int __cdecl __crtMessageBoxW(LPCTSTR lpText, LPCTSTR lpCaption,UINT uType)
{
    static int (APIENTRY *pfnMessageBoxA)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
    static HWND (APIENTRY *pfnGetActiveWindow)(void) = NULL;
    static HWND (APIENTRY *pfnGetLastActivePopup)(HWND) = NULL;

    HWND hWndParent = NULL;

    if (NULL == pfnMessageBoxA)
    {
        HANDLE hlib = LoadLibrary( TEXT("user32.dll"));

        if (NULL == hlib || NULL == (pfnMessageBoxA = 
            (int(APIENTRY *)(HWND, LPCTSTR, LPCTSTR, UINT))
            GetProcAddress((struct HINSTANCE__ *)hlib, "MessageBoxW")))
            return 0;

        pfnGetActiveWindow = (HWND (APIENTRY *)(void))
            GetProcAddress((struct HINSTANCE__ *)hlib, "GetActiveWindow");

        pfnGetLastActivePopup = (HWND (APIENTRY *)(HWND))
            GetProcAddress((struct HINSTANCE__ *)hlib, "GetLastActivePopup");
    }

    if (pfnGetActiveWindow)
        hWndParent = (*pfnGetActiveWindow)();

    if (hWndParent != NULL && pfnGetLastActivePopup)
        hWndParent = (*pfnGetLastActivePopup)(hWndParent);

    return (*pfnMessageBoxA)(hWndParent, lpText, lpCaption, uType);
}

int __cdecl AssertMessageBox()
{
    static int (APIENTRY *pfnMessageBoxW)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
    static HWND (APIENTRY *pfnGetActiveWindow)(void) = NULL;
    static HWND (APIENTRY *pfnGetLastActivePopup)(HWND) = NULL;

    HWND hWndParent = NULL;

    if (NULL == pfnMessageBoxW)
    {
        HANDLE hlib = LoadLibrary( TEXT("user32.dll") );
        if (NULL == hlib || NULL == (pfnMessageBoxW = 
            (int (APIENTRY *)(HWND, LPCTSTR, LPCTSTR, UINT))
            GetProcAddress((struct HINSTANCE__ *)hlib, "MessageBoxW")))
            return 0;

        pfnGetActiveWindow = (HWND (APIENTRY *)(void))
            GetProcAddress((struct HINSTANCE__ *)hlib, "GetActiveWindow");

        pfnGetLastActivePopup = (HWND (APIENTRY *)(HWND))
            GetProcAddress((struct HINSTANCE__ *)hlib, "GetLastActivePopup");
    }

    if (pfnGetActiveWindow)
        hWndParent = (*pfnGetActiveWindow)();

    if (hWndParent != NULL && pfnGetLastActivePopup)
        hWndParent = (*pfnGetLastActivePopup)(hWndParent);

    return (*pfnMessageBoxW)(
                hWndParent, 
                _ASSERT::AskToInvokeAgain,
                _ASSERT::AssertWindowTitle, 
                MB_YESNO|MB_DEFBUTTON2);
}

static void __cdecl PushToClipboard( const TCHAR* buffer )
{
    if( OpenClipboard( NULL ) )
    {
        HGLOBAL hMem = GlobalAlloc( GHND|GMEM_DDESHARE, STRLEN(buffer)*2 );
        if(hMem)
        {
            TCHAR *pMem = (TCHAR*)GlobalLock( hMem );
            STRCPY( pMem, STRLEN(buffer), buffer );
            GlobalUnlock( hMem );
            EmptyClipboard();
            SetClipboardData( CF_UNICODETEXT, hMem );
        }
        CloseClipboard();
    }
}

 bool AssertMsgFunc(const TCHAR *exp, const TCHAR *msg, const TCHAR *func, const TCHAR *file, const int& line)
{
    if(!exp) 
		return false;

	TCHAR strAssertMsg[0xffff]={0,};
    TCHAR bufTime[0xff]=TEXT("");
    struct tm* curTime= CmTime::GetLocalTimes();    
	if(curTime)
		SPRINTF( bufTime, SIZE_TRACE_TIME, TEXT("[%02d:%02d:%02d] "), curTime->tm_hour, curTime->tm_min, curTime->tm_sec);
	static TCHAR numBuf[0xff];
	NUMBER_TO_CHAR_UNI(line, numBuf, 0xff);

	SPRINTF( strAssertMsg, 0xffff, 
		TEXT("Day: %s\r\nFile: %s\r\nLine: %s\r\nFUNCTION: %s\r\nExpr: %s\r\nMSG: %s\r\n")
		,bufTime
		,file
		,numBuf 
		,func
		,exp
		,(msg!=NULL)?msg:TEXT("") );

	::OutputDebugString( strAssertMsg);
	PushToClipboard( strAssertMsg );
    int nCode = __crtMessageBoxW( 
                strAssertMsg,
                _ASSERT::AssertWindowTitle, 
                MB_SETFOREGROUND | MB_APPLMODAL | MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION);

    if (nCode == IDABORT) 
    {
        fflush(NULL);
        _exit(3);
    }
    if (nCode == IDRETRY) 
    {
        fflush(NULL);        
		__AsmBreak();	//__asm int 3
        return true;
    } // invoke debugger
    if (nCode == IDIGNORE) 
    {
        return false;
    } // do nothing

    return false;
}

void AssertFailMsg(const UINT32& line, TCHAR* pFunc, TCHAR *pFile, TCHAR* format, ...)
{
    TCHAR buf[MAX_ASSERT_MSG_SIZE]={0,}; 
    CmVAR_ARGS( buf, CmCOUNTOF(buf), format);     
    AssertMsgFunc( TEXT("ASSERTFAIL_MSG"), buf, pFunc, pFile, line );
}

void AssertMsg(bool checkAssert, TCHAR* exp, const UINT32& line, TCHAR* pFunc, TCHAR *pFile, TCHAR* format, ...)
{
    if(checkAssert) 
		return;

    TCHAR buf[MAX_ASSERT_MSG_SIZE]={0,}; 
    CmVAR_ARGS( buf, CmCOUNTOF(buf), format);         
    AssertMsgFunc( exp, buf, pFunc, pFile, line );
}

void __AsmBreak()
{
	__debugbreak();
}

/*------------------------------------------------------------------------

------------------------------------------------------------------------*/
